package com.xu.tools.util;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.http.HttpServletRequest;
import java.net.*;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.Objects;

/**
 * 获取IP地址
 *
 * @author xuguan
 * @since 2023/7/28
 */
public class IpUtil {

    public static final Logger log = LoggerFactory.getLogger(IpUtil.class);

    private static final List<String> HEADERS = new ArrayList<String>() {{
        add("X-Forwarded-For");
        add("Proxy-Client-Ip");
        add("WL-Proxy-Client-Ip");
        add("HTTP_X_FORWARDED_FOR");
        add("HTTP_X_FORWARDED");
        add("HTTP_X_CLUSTER_CLIENT_IP");
        add("HTTP_CLIENT_IP");
        add("HTTP_FORWARDED_FOR");
        add("HTTP_FORWARDED");
        add("HTTP_VIA");
        add("REMOTE_ADDR");
        add("X_Real_IP");
    }};

    /**
     * 获取客户端IP地址
     */
    public static String getClientIp(HttpServletRequest request) {
        String ip = "";
        for (String header : HEADERS) {
            ip = request.getHeader(header);
            if (Objects.nonNull(ip) && !"".equals(ip.trim()) && !"unknown".equalsIgnoreCase(ip)) {
                // 如果有多个代理地址, 取第一个地址
                if (ip.contains(",")) {
                    ip = ip.substring(0, ip.indexOf(","));
                }
                return ip;
            }
        }
        ip = request.getRemoteAddr();
        if ("localhost".equalsIgnoreCase(ip)
                || "127.0.0.1".equalsIgnoreCase(ip)
                || "0:0:0:0:0:0:0:1".equalsIgnoreCase(ip)) {
            ip = getLocalIp();
        }
        return ip;
    }

    /**
     * 获取本地IP地址
     */
    public static String getLocalIp() {
        String ip = "";
        try {
            Enumeration<NetworkInterface> ifces = NetworkInterface.getNetworkInterfaces();
            while (ifces.hasMoreElements()) {
                NetworkInterface ifc = ifces.nextElement();
                // loopback interface回环接口是一种特殊的网络接口, 其目的是将数据包发送给同一台机器上的其他进程, 而不需要通过物理网络. 在IPV4中, 回环接口的IP地址通常是127.0.0.1, 在IPV6中是::1
                if (ifc.isLoopback() || ifc.isVirtual() || !ifc.isUp()) {
                    continue;
                }

                Enumeration<InetAddress> addresses = ifc.getInetAddresses();
                while (addresses.hasMoreElements()) {
                    InetAddress address = addresses.nextElement();
                    if (address != null && !address.isLoopbackAddress() && address instanceof Inet4Address) {
                        if (address.isSiteLocalAddress()) {
                            return address.getHostAddress();
                        }
                        if ("".equals(ip)) {
                            ip = address.getHostAddress();
                        }
                    }
                }
            }
        } catch (SocketException e) {
            log.error("获取网卡信息失败");
        }

        if ("".equals(ip)) {
            try {
                ip = InetAddress.getLocalHost().getHostAddress();
            } catch (UnknownHostException e) {
                log.error("获取本地IP地址失败");
                ip = "127.0.0.1";
            }
        }

        return ip;
    }
}
